﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.ComponentModel;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

using agree.schema;

using alib.BitArray;
using alib.Collections;
using alib.Collections.ReadOnly;
using alib.Combinatorics;
using alib.Debugging;
using alib.Enumerable;
using alib.Reflection;
using alib.String;

namespace agree.transfer_prototype
{
	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	/// 
	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

	[DebuggerDisplay("{ToString(),nq}")]
	public class rule
	{
		public rule(String name)
		{
			this.Name = name;
			build_names = new Dictionary<String, type_base>();
			src_rels = new _rels<rule_src_rel>();
			tgt_rels = new _rels<rule_tgt_rel>();
		}

		Dictionary<String, type_base> build_names;

		public readonly String Name;

		public readonly _rels<rule_src_rel> src_rels;
		public readonly _rels<rule_tgt_rel> tgt_rels;

		public void set_value(rule_rel rel, int i_arg, String s)
		{
			type_base t;
			if (!build_names.TryGetValue(s, out t))
			{
				t = type_base.IsVar(s) ? (type_base)new Var(s.Substring(0, 1)) : new type(s);
				build_names.Add(s, t);
			}

			if (rel is rule_src_rel)
			{
				if (rel.ix == -1)
					src_rels.Add((rule_src_rel)rel);
				src_rels[rel.ix].values[i_arg] = t;
			}
			else
			{
				if (rel.ix == -1)
					tgt_rels.Add((rule_tgt_rel)rel);
				tgt_rels[rel.ix].values[i_arg] = t;
			}
		}

		public IEnumerable<rule_rel> all_rels { get { return src_rels.Cast<rule_rel>().Concat(tgt_rels); } }
	};


	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	/// 
	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

	public interface input_mrs : IReadOnlyList<inp_rel>
	{
	}

	[DebuggerDisplay("{ToString(),nq}")]
	public class __input_mrs : _rels<inp_rel>, input_mrs
	{
		public __input_mrs()
		{
			build_names = new Dictionary<String, type_base>();
		}

		Dictionary<String, type_base> build_names;

		public void set_value(inp_rel rel, int i_arg, String s)
		{
			type_base t;
			if (!build_names.TryGetValue(s, out t))
			{
				t = type_base.IsVar(s) ? (type_base)new Var(s.Substring(0, 1)) : new type(s);
				build_names.Add(s, t);
			}

			if (rel.ix == -1)
				this.Add(rel);
			this[rel.ix].values[i_arg] = t;
		}
	};

	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	/// 
	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////


	[DebuggerDisplay("hyp #{id}  {tgt_rels.ToString(),nq}")]
	public class xfer_hyp : identity_base, IEnumerable<RuleApplication>
	{
		static int next_id;
		public xfer_hyp(IIdentity prv)
			: base(prv)
		{
			this.tgt_rels = new _rels<locus>();
			this.id = Interlocked.Increment(ref next_id);
			TransferExecutor.print.WriteLine("new hyp #{0}", id);
		}
		public xfer_hyp(IIdentity prv, xfer_hyp h_old, RuleApplication ra)
			: this(prv)
		{
			this.parent_hyp = h_old;
			this.ra = ra;

			foreach (var loc in h_old.tgt_rels)
				this.tgt_rels.Add(new locus(loc));
		}
		public readonly int id;

		public xfer_hyp parent_hyp;

		public readonly RuleApplication ra;

		public _rels<locus> tgt_rels;

		public bool Contains(rule r_seek)
		{
			rule r;
			xfer_hyp h = this;
			do
				if ((r = h.ra.rule) == r_seek)
					return true;
			while ((h = h.parent_hyp) != null);
			return false;
		}
		public bool Contains(RuleApplication ra_seek)
		{
			xfer_hyp h = this;
			do
				if (h.ra.Equals(ra_seek))
					return true;
			while ((h = h.parent_hyp) != null);
			return false;
		}

		public IEnumerator<RuleApplication> GetEnumerator()
		{
			for (xfer_hyp h = this; h.ra.rule != null; h = h.parent_hyp)
				yield return h.ra;
		}

		IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); }

		public String Report()
		{
			StringBuilder sb = new StringBuilder();
			foreach (locus loc in tgt_rels)
				sb.Append(loc.ToString());
			sb.AppendLine();
			foreach (var ra in this.Reverse())
				sb.AppendLine(String.Format("{0}", ra.ToString()));
			return sb.ToString();
		}

		///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		/// 
		public void show_hyp(System.IO.TextWriter tw)
		{
			tw.WriteLine("--- hypothesis {0} ---", this.id);
			foreach (var ra in this.Reverse())
				tw.WriteLine(String.Format("{0}", ra.ToString()));

			tgt_rels.show_rels(tw);
		}

		public override String ToString()
		{
			return tgt_rels.StringJoin(" ");
		}
	};
}